package com.jacobson.core.base.delegate

import android.app.Activity
import android.app.Application
import android.app.Service
import android.content.ComponentCallbacks2
import android.content.ContentProvider
import android.content.Context
import android.content.res.Configuration
import androidx.fragment.app.FragmentManager
import com.jacobson.core.App
import com.jacobson.core.di.components.AppComponent
import com.jacobson.core.di.components.DaggerAppComponent
import com.jacobson.core.di.modules.GlobalConfigurationModule
import com.jacobson.core.framework.AndroidManifestParser
import com.jacobson.core.framework.AppConfiguration
import com.jacobson.core.utils.Density
import com.jacobson.core.utils.DeviceUtil
import com.jacobson.core.utils.Preconditions
import com.jacobson.core.widget.logger.LoggerFactory
import java.util.*
import javax.inject.Inject
import javax.inject.Named


/**
 * ================================================
 * [Application]代理
 * @author Wucz on 2018/7/16 9:17
 * ================================================
 */

class AppDelegate(
        val context: Context
) : AppLifecycle, App {
    private val logger = LoggerFactory.getLogger()
    private var appLifecycleList: MutableList<AppLifecycle> = ArrayList()
    private var activityLifecycleList: MutableList<Application.ActivityLifecycleCallbacks> = ArrayList()
    private var fragmentLifecycleList: MutableList<FragmentManager.FragmentLifecycleCallbacks> = ArrayList()
    private var appConfigurations: MutableList<AppConfiguration> = AndroidManifestParser(context).parse()
    private lateinit var application: Application
    private val appComponent: AppComponent by lazy {
        DaggerAppComponent.builder()
                .application(application)
                .globalConfigurationModule(obtainGlobalConfigurationModule())
                .build()
    }

    private var componentCallbacks: AppComponentCallbacks? = null

    @Inject
    @field:[Named("ActivityLifecycle")]
    internal lateinit var activityLifecycle: Application.ActivityLifecycleCallbacks

    @Inject
    @field:[Named("RxActivityLifecycle")]
    internal lateinit var rxActivityLifecycle: Application.ActivityLifecycleCallbacks

    @Inject
    @field:Named("densitySupport")
    internal lateinit var densitySupport: String

    @Inject
    internal lateinit var daggerSupportFragmentLifecycleList: MutableList<FragmentManager.FragmentLifecycleCallbacks>

    init {
        //解析AndroidManifest.xml中值为[AndroidManifestParser.APP_CONFIGURATION_VALUE]的meta-data配置
        //遍历所有配置类，执行每一个配置类的方法
        appConfigurations.forEach {
            //注入开发者实现的[Application]生命周期方法回调
            it.injectAppLifecycle(context, appLifecycleList)
            //注入开发者实现的[Activity]的生命周期回调
            it.injectActivityLifecycle(context, activityLifecycleList)
            //注入开发者实现的[Fragment]的生命周期回调
            it.injectFragmentLifecycle(context, fragmentLifecycleList)
        }
    }

    override fun attachBaseContext(base: Context) {
        //回调[Application.attachBaseContext]生命周期给开发者
        appLifecycleList.forEach {
            it.attachBaseContext(base)
        }
    }

    override fun onCreate(application: Application) {
        this.application = application

        //注入实例
        appComponent.inject(this)
        //回调Inject
        injectAppConfigurations()
        DeviceUtil.init(application)
        daggerSupportFragmentLifecycleList.addAll(fragmentLifecycleList)
        densitySupport.takeIf { it.toBoolean() }?.let { Density.setDensity(application) }
        //注册框架内部实现的Activity生命周期逻辑
        logger.d("densitySupport: ${densitySupport.toBoolean()}  activityLifecycle: ${activityLifecycle.javaClass.simpleName} rxActivityLifecycle: ${rxActivityLifecycle.javaClass.simpleName}")
        activityLifecycle.let { application.registerActivityLifecycleCallbacks(it) }
        //注册框架内部实现的RxLifecycle逻辑
        rxActivityLifecycle.let { application.registerActivityLifecycleCallbacks(it) }

        //注册开发者扩展的Activity生命周期逻辑
        activityLifecycleList.forEach {
            this.application.registerActivityLifecycleCallbacks(it)
        }
        componentCallbacks = AppComponentCallbacks(application, appComponent)
        //注册内存紧张时回调了来释放部分内存
        application.registerComponentCallbacks(componentCallbacks)
        //回调开发者注册的APP生命周期[Application.onCreate]方法
        appLifecycleList.forEach {
            it.onCreate(application)
        }
    }


    override fun onTerminate(application: Application) {
        application.run {
            activityLifecycle.let { unregisterActivityLifecycleCallbacks(it) }
            rxActivityLifecycle.let { unregisterActivityLifecycleCallbacks(it) }
            componentCallbacks?.let { unregisterComponentCallbacks(it) }
            activityLifecycleList.forEach { unregisterActivityLifecycleCallbacks(it) }
            appLifecycleList.forEach { it.onTerminate(this) }
        }
        componentCallbacks = null
        activityLifecycleList.clear()
        appLifecycleList.clear()
    }

    override fun provideAppComponent(): AppComponent {
        Preconditions.checkNonNull(appComponent,
                "${AppComponent::class.qualifiedName} 实例为空，" +
                        "请先在${Application::class.qualifiedName}#onCreate()方法中" +
                        "调用 ${AppDelegate::class.qualifiedName}#onCreate(Application)方法")
        return appComponent
    }

    private fun obtainGlobalConfigurationModule(): GlobalConfigurationModule {
        val builder = GlobalConfigurationModule.newBuilder()
        appConfigurations.forEach {
            it.applyOptions(context, builder)
        }
        return builder.build()
    }

    private fun injectAppConfigurations() {
        appConfigurations.forEach {
            it.inject(context, this, appComponent)
        }
    }

    /**
     * [ComponentCallbacks2]是一个细粒度的内存回收管理回调
     */
    private class AppComponentCallbacks(
            val application: Application,
            val appComponent: AppComponent
    ) : ComponentCallbacks2 {
        /**
         * 在你的 App 生命周期的任何阶段, [ComponentCallbacks2.onTrimMemory] 发生的回调都预示着你设备的内存资源已经开始紧张
         * 你应该根据 [ComponentCallbacks2.onTrimMemory] 发生回调时的内存级别来进一步决定释放哪些资源
         * [ComponentCallbacks2.onTrimMemory] 的回调可以发生在 [Application]、[Activity]、[Service]、[ContentProvider]、[Fragment]
         *
         * @param level 内存级别
         * @see [level 官方文档](https://developer.android.com/reference/android/content/ComponentCallbacks2.html.TRIM_MEMORY_RUNNING_MODERATE)
         */
        override fun onTrimMemory(level: Int) {
            //状态1. 当开发者的 App 正在运行
            //设备开始运行缓慢, 不会被 kill, 也不会被列为可杀死的, 但是设备此时正运行于低内存状态下, 系统开始触发杀死 LRU 列表中的进程的机制
            //                case TRIM_MEMORY_RUNNING_MODERATE:


            //设备运行更缓慢了, 不会被 kill, 但请你回收 unused 资源, 以便提升系统的性能, 你应该释放不用的资源用来提升系统性能 (但是这也会直接影响到你的 App 的性能)
            //                case TRIM_MEMORY_RUNNING_LOW:


            //设备运行特别慢, 当前 App 还不会被杀死, 但是系统已经把 LRU 列表中的大多数进程都已经杀死, 因此你应该立即释放所有非必须的资源
            //如果系统不能回收到足够的 RAM 数量, 系统将会清除所有的 LRU 列表中的进程, 并且开始杀死那些之前被认为不应该杀死的进程, 例如那个包含了一个运行态 Service 的进程
            //                case TRIM_MEMORY_RUNNING_CRITICAL:


            //状态2. 当前 App UI 不再可见, 这是一个回收大个资源的好时机
            //                case TRIM_MEMORY_UI_HIDDEN:


            //状态3. 当前的 App 进程被置于 Background LRU 列表中
            //进程位于 LRU 列表的上端, 尽管你的 App 进程并不是处于被杀掉的高危险状态, 但系统可能已经开始杀掉 LRU 列表中的其他进程了
            //你应该释放那些容易恢复的资源, 以便于你的进程可以保留下来, 这样当用户回退到你的 App 的时候才能够迅速恢复
            //                case TRIM_MEMORY_BACKGROUND:


            //系统正运行于低内存状态并且你的进程已经已经接近 LRU 列表的中部位置, 如果系统的内存开始变得更加紧张, 你的进程是有可能被杀死的
            //                case TRIM_MEMORY_MODERATE:


            //系统正运行于低内存的状态并且你的进程正处于 LRU 列表中最容易被杀掉的位置, 你应该释放任何不影响你的 App 恢复状态的资源
            //低于 API 14 的 App 可以使用 onLowMemory 回调
            //                case TRIM_MEMORY_COMPLETE:
        }

        override fun onConfigurationChanged(newConfig: Configuration) {

        }

        /**
         * 当系统开始清除 LRU 列表中的进程时, 尽管它会首先按照 LRU 的顺序来清除, 但是它同样会考虑进程的内存使用量, 因此消耗越少的进程则越容易被留下来
         * [ComponentCallbacks2.onTrimMemory] 的回调是在 API 14 才被加进来的, 对于老的版本, 你可以使用 [ComponentCallbacks2.onLowMemory] 方法来进行兼容
         * [ComponentCallbacks2.onLowMemory] 相当于 `onTrimMemory(TRIM_MEMORY_COMPLETE)`
         *
         * @see .TRIM_MEMORY_COMPLETE
         */
        override fun onLowMemory() {
            //系统正运行于低内存的状态并且你的进程正处于 LRU 列表中最容易被杀掉的位置, 你应该释放任何不影响你的 App 恢复状态的资源
        }

    }
}